<?php

namespace Xin\WorkmanServer\Laravel;

use Illuminate\Foundation\Application as LaravelApplication;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
use Laravel\Lumen\Application as LumenApplication;
use Workerman\Protocols\Http\Request as WorkermanRequest;
use Xin\WorkmanServer\HttpServer;
use Xin\WorkmanServer\Laravel\Console\ServerCommand;
use Xin\WorkmanServer\WebsocketServer;

class WorkermanServiceProvider extends ServiceProvider
{
	/**
	 * 是否延时加载提供器
	 * @var bool
	 */
	protected $defer = true;

	/**
	 * @return void
	 */
	public function register()
	{
		$this->registerHttpServer();
		$this->registerWebsocketServer();

		$this->commands([
			ServerCommand::class,
		]);
	}

	/**
	 * 注册HttpServer服务
	 * @return void
	 */
	protected function registerHttpServer()
	{
		$config = $this->app['config']['workerman.http'];
		if (!$config) {
			return;
		}

		$this->app->singleton('http_server', function () use ($config) {
			$httpServer = new HttpServer($config);

			$httpServer->setRequestResolver(function (WorkermanRequest $requestInfo, $serverInfo) {
				// 转换成 Laravel Request
				$request = Request::create(
					$requestInfo->uri(),
					$requestInfo->method(),
					$requestInfo->post(),
					$requestInfo->cookie(),
					$requestInfo->file(),
					$_SERVER + $serverInfo,
					$requestInfo->rawBody()
				);

				$request->attributes->set('connection', $requestInfo->connection);

				return $request;
			});

			$httpServer->setHttpHandler(function (Request $request, $isKeepAliveRequest) {
				// 获取应用实例
				$app = class_exists(LaravelApplication::class) ? LaravelApplication::getInstance() : LumenApplication::getInstance();

				// 注入新的请求实例
				$app->instance('request', $request);

				// 处理请求
				return $app->handle($request);
			});

			return $httpServer;
		});
		$this->app->alias('http_server', HttpServer::class);
	}

	/**
	 * 注册Websocket服务
	 * @return void
	 */
	protected function registerWebsocketServer()
	{
		$config = $this->app['config']['workerman.websocket'];
		if (!$config) {
			return;
		}

		$this->app->singleton('websocket_server', function () use ($config) {
			return new WebsocketServer($config);
		});

		$this->app->alias('websocket_server', WebsocketServer::class);
	}

	/**
	 * Bootstrap the application services.
	 *
	 * @return void
	 */
	public function boot()
	{
		$this->optimizeRequest();

		if ($this->app->runningInConsole()) {
			$this->booted(function () {
				$this->bootInConsole();
			});
		}
	}

	/**
	 * 优化请求器
	 * @return void
	 */
	protected function optimizeRequest()
	{
		Request::enableHttpMethodParameterOverride();
		//        Request::macro('setConnection', function ($connection) {
		//            return $this->attributes->set('connection', $connection);
		//        });
		Request::macro('getConnection', function () {
			return $this->attributes->get('connection');
		});
		Request::macro('setAutoCloseConnection', function ($noCloseConnection) {
			return $this->attributes->set('autoCloseConnection', $noCloseConnection);
		});
		Request::macro('getAutoCloseConnection', function () {
			return $this->attributes->get('autoCloseConnection', true);
		});
	}

	/**
	 * @return void
	 */
	protected function bootInConsole()
	{
		// $schedule = $this->app->make(Schedule::class);
	}

	/**
	 * @inerhitDoc
	 */
	public function provides()
	{
		return [
			'http_server',
			'websocket_server',
			HttpServer::class,
			WebsocketServer::class,
		];
	}
}
